# Python 中有两种类型的循环: while 循环 和 for 循环

# 1.while 循环
# while 循环 是： 检查一个条件表达式，只要条件表达式计算结果为 True 时， 就执行下面缩进的代码。
# 如此反复，直到条件表达式计算结果为 False 时，结束 循环。
i = 1
while i <= 10:
    print(i)
    i += 1

# 2.for 循环
# for 循环 通常是从一个 sequence 类型，比如 字符串、列表 或者 元组中 依次取出每个元素进行操作

# 2.1.for 循环的用法
studentAges = ['小王:17', '小赵:16', '小李:17', '小孙:16', '小徐:18']
for student in studentAges:
    print(student)

# 2.2.循环 n 次
# 可以使用 range(arg1, arg2, arg3)，它有三个参数,
# arg1：取值的开始范围
# arg2：取值的结束范围
# arg3：取值的步长
for n1 in range(100):
    print(n1)  # 其中 n1 依次为 0,1,2,3,4... 直到 99

for n2 in range(50, 101):
    print(n2)  # 其中 n2 依次为 50，51，52... 直到 100

for n3 in range(50, 101, 5):
    print(n3)  # 其中 n3 依次为 50, 55, 60, 65... 这样每次增加5， 直到 100

# 注意：
# 和 Python 2 不同， Python 3 中的 range 并不是一个函数，不会返回一个数字列表。
# Python 3 中的 range 是一个 类。
# 如果你想返回一个 从 0 到 10 的数字列表， 可以这样写:
numList = list(range(11))
print(numList)

# 2.3.enumerate 函数
# 有的时候，在使用 for 循环从列表或者元组中遍历元素的时候，除了要获取每个元素，还需要得到每个元素在列表元组里面的索引。
studentAges1 = ['小王:17', '小赵:16', '小李:17', '小孙:16', '小徐:18']
# enumerate (studentAges1) 每次迭代返回 一个元组，里面有两个元素，依次是 元素的索引和元素本身
for idx, student in enumerate(studentAges1):
    if int(student.split(':')[-1]) > 17:
        print(idx)

# 3.break
# 3.1.break 终止循环
# 有时，我们循环体内的代码在发现某种条件满足的时候，需要终止循环。
# 3.1.1.while 循环中 break
i1 = 1
while i1 < 10:
    print(i1)
    i1 += 1
    if i1 == 8:
        break
    print(i1)

print('while循环结束')

# 3.1.2.for 循环中 break
for i2 in range(10):
    print(i2)
    if i2 == 8:
        break
    print(i2)

print('for循环结束')


# 3.2.函数中的 break
# 函数中的循环体内的代码， 使用 return 和 break 都可以从循环中跳出。
# 但是，break 只是 跳出循环， 如果循环后面还有代码， 会进行执行，如下：
def whileTest():
    i4 = 1
    while i4 < 10:
        print(i4)
        i4 += 1
        if i4 == 8:
            break
        print(i4)

    print('末尾语句')  # 执行该函数，发现，还会打印出 末尾语句 这句话


whileTest()


# 4.return
# return 只能用在函数里面， 表示 从函数中返回。代码主体部分是不能用 return 的。
# 比如，下面的代码执行起来就会报错，因为 return 是表示从函数中返回，它 是不能用在 函数外面的。
i3 = 1
while i3 < 10:
    print(i3)
    i3 += 1
    if i3 == 8:
        return
    print(i3)


# return 会从函数里面立即返回， 函数体内的后续任何代码都不执行了，如下:
def whileTest1():
    i4 = 1
    while i4 < 10:
        print(i4)
        i4 += 1
        if i4 == 8:
            return
        print(i4)

    print('末尾语句')  # 执行该函数，发现，不会打印出 末尾语句 这句话


whileTest1()

# 5.continue
# 有时，我们循环体内的代码在发现某种条件满足的时候，不是要终止整个循环，而是只结束当前这一轮循环，后面还要继续循环的执行。
i5 = 1
while i5 < 10:
    print('i：%s' % i5)
    i5 += 1
    if i5 == 8:
        continue
    print(i5)

print('while循环结束')

# 6.break，return，continue 总结：
# return 也能结束循环，但只能在函数中使用，表示从函数中返回，不管函数中还有没有代码，都不继续执行了。
# break 是结束整个循环，如果跳出循环后，后面还有代码，会继续执行循环外的代码。
# continue 只是结束当前这次的循环，后续的循环还是要继续执行。

# 7.列表推导式
# 把一个列表里面的每个元素， 经过相同的处理 ，生成另一个列表。
# 比如：一个列表1，里面都是数字，我们需要生成一个新的列表 B，依次存放列表A中每个元素的平方。
# 7.1.for 循环处理
list1 = [1, 2, 3, 4, 5, 6]
list2 = []
for num in list1:
    list2.append(num * num)
print(list2)

# 7.2.列表推导式处理
list11 = [1, 2, 3, 4, 5, 6]
list22 = [num ** 2 for num in list11]
print(list22)

# 8.循环嵌套
# 下面有两个列表 分别代表 刘备 和 曹操 麾下的猛将。
# 让 list1 中每员大将和 list2 中的每员大将 都互相厮杀一次，打印出 A 大战 B。
# 这是典型的 2个列表元素两两组合的问题， 需要用到循环的嵌套。
# 所谓循环的嵌套，就是循环里面还有循环。
list13 = ['关羽', '张飞', '赵云', '马超', '黄忠']
list23 = ['典韦', '许褚', '张辽', '夏侯惇', '夏侯渊']
for member1 in list13:
    for member2 in list23:
        print(f'{member1} 大战 {member2}')

# 9.练习1
# 有如下的2个字符串：
str1 = '''
熊宁
杰益

王伟伟

青芳

玉琴
焦候涛
莫福
杨高旺
唐欢欢
韩旭
'''

str2 = '''
焦候涛 
熊宁 
玉琴 

骆龙 

韩旭 
杨高旺

杰益  

莫福  

伟伟

李福  
'''
# 请写一个程序找出 str1 中所有 str2 中不存在的人名，并且找出 str2 中所有 str1 中不存在的人名
# step1：字符串转列表，并去除多余的 ''
newStr1 = list(set(str1.split('\n')))
newStr2 = list(set(str2.split('\n')))

# step2：去除最后残留的 ''
newStr1.remove('')
newStr2.remove('')

print(f'字符串str1转换后的原始列表：{newStr1}')
print(f'字符串str2转换后的原始列表：{newStr2}')

# step3：定义接收重名的列表
nameList = []

# step4：遍历原始列表数据，找出都存在的人名，组成一个列表
for people1 in newStr1:
    for people2 in newStr2:
        if people1.strip() == people2.strip():
            # str1 中 str2 中存在的人名
            nameList.append(people2)

print(f'str1和str2中的重名列表：{nameList}')

# step5：遍历重名列表，将其从原始列表中剔除，剩下的就是各原始列表中不互相存在的人名
for pubPeople in nameList:
    newStr1.remove(pubPeople.strip())
    newStr2.remove(pubPeople)

print(f'str1剔除重名后的列表：{newStr1}')
print(f'str2剔除重名后的列表：{newStr2}')

# step6：结果
print(f'结果：str1 中 str2 中不存在的人名有：{"、".join(newStr1)}，str2 中 str1 中不存在的人名有：{"、".join(newStr2)}')

# 10.练习2
# 有如下的字符串，记录了三国人物的名字和年龄
ageTable = '''
    诸葛亮, 28
    刘备, 48
    刘琦, 25
    赵云, 32
    张飞, 43
    关羽, 45
'''
# 请写一个程序将其中 30岁以上和以下的人分别打印出来，类似这样
# 大于等于30岁的人有：
# 刘备
# 赵云
# 张飞
# 关羽
#
# 小于30岁的人有：
# 诸葛亮
# 刘琦

# step1：将字符串按行转化为列表
ageTableList = ageTable.splitlines()
ageTableList.remove('')
print(ageTableList)

# step2：定义两个列表，分别接收30岁以上（包含30岁）及30岁以下的人名
overList = []
lowList = []

# step3：遍历原始列表，判断30岁以上（包含30岁）及30以下的人有哪些
for person in ageTableList:
    personInfoList = person.strip().split(', ')
    print(personInfoList)

    if int(personInfoList[1]) >= 30:
        overList.append(personInfoList[0])
    else:
        lowList.append(personInfoList[0])

print(f'大于等于30岁的人名列表：{overList}')
print(f'小于30岁的人名列表：{lowList}')

personStr1 = "\n".join(overList)
personStr2 = "\n".join(lowList)

# step4：结果打印
print(f'大于等于30岁的人有：\n{personStr1}\n\n小于30岁的人有：\n{personStr2}')
